package org.example.liuy.handler;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import lombok.extern.slf4j.Slf4j;
import org.example.liuy.annotation.GetMapping;
import org.example.liuy.annotation.PostMapping;
import org.example.liuy.annotation.RequestMapping;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class AnnotationHandlerMapping {
    private final HttpServer server;
    private final Map<String, HandlerMethod> handlerMethods = new ConcurrentHashMap<>();

    public AnnotationHandlerMapping(HttpServer server) {
        this.server = server;
    }

    public void scanAndRegisterHandlers(String basePackage, Object... dependencies) {
        log.info("Scanning controllers in package: {}", basePackage);
        Set<Class<?>> controllerClasses = ComponentScannerHelper.scanControllers(basePackage);

        for (Class<?> controllerClass : controllerClasses) {
            try {
                Object controllerInstance = ComponentScannerHelper.instantiateController(controllerClass, dependencies);
                doRegisterHandler(controllerInstance);
            } catch (Exception e) {
                log.error("Failed to instantiate controller: {}", controllerClass.getName(), e);
            }
        }
    }



    /**
     * 判断路径是否为动态路径（包含路径变量）
     * @param path 路径
     * @return 是否为动态路径
     */
    private boolean isDynamicPath(String path) {
        // 检查路径中是否包含 {variable} 形式的路径变量
        return path != null && path.contains("{") && path.contains("}");
    }

    /**
     * 执行控制器注册
     * @param handler 控制器实例
     */
    private void doRegisterHandler(Object handler) {
        Class<?> handlerClass = handler.getClass();
        String classPath = "";

        if (handlerClass.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping classMapping = handlerClass.getAnnotation(RequestMapping.class);
            classPath = classMapping.value();
        }

        Method[] methods = handlerClass.getDeclaredMethods();
        for (Method method : methods) {
            RequestMapping methodMapping = null;

            // 检查 RequestMapping 注解
            if (method.isAnnotationPresent(RequestMapping.class)) {
                methodMapping = method.getAnnotation(RequestMapping.class);
            }
            // 检查 GetMapping 注解
            else if (method.isAnnotationPresent(GetMapping.class)) {
                GetMapping getMapping = method.getAnnotation(GetMapping.class);
                methodMapping = new RequestMapping() {
                    @Override
                    public Class<? extends java.lang.annotation.Annotation> annotationType() {
                        return RequestMapping.class;
                    }

                    @Override
                    public String value() {
                        return getMapping.value();
                    }

                    @Override
                    public String method() {
                        return "GET";
                    }
                };
            }
            // 检查 PostMapping 注解
            else if (method.isAnnotationPresent(PostMapping.class)) {
                PostMapping postMapping = method.getAnnotation(PostMapping.class);
                methodMapping = new RequestMapping() {
                    @Override
                    public Class<? extends java.lang.annotation.Annotation> annotationType() {
                        return RequestMapping.class;
                    }

                    @Override
                    public String value() {
                        return postMapping.value();
                    }

                    @Override
                    public String method() {
                        return "POST";
                    }
                };
            }

            if (methodMapping != null) {
                String fullPath = normalizePath(classPath + methodMapping.value());
                String key = methodMapping.method() + ":" + fullPath;
                if(server==null || isDynamicPath(fullPath)){
                    handlerMethods.put(key, new HandlerMethod(handler, method));
                }else{
                    ControllerMethodHandler controllerHandler = new ControllerMethodHandler(handler, method);
                    HttpHandler rateLimitHandler = new RateLimitHandler(controllerHandler);
                    HttpHandler loggingHandler = new RequestLoggingHandler(rateLimitHandler);
                    server.createContext(fullPath, loggingHandler);
                }
                log.info("Mapped {} {} to {}.{}",
                        methodMapping.method(), fullPath, handlerClass.getSimpleName(), method.getName());
            }
        }
    }

    /**
     * 处理 HTTP 请求
     * @param exchange HttpExchange 对象
     * @throws IOException IO异常
     */
    public void handleRequest(HttpExchange exchange) throws IOException {
        String path = exchange.getRequestURI().getPath();
        String method = exchange.getRequestMethod();

        // 查找匹配的处理器
        HandlerMethod handlerMethod = findHandlerMethod(method, path);

        if (handlerMethod != null) {
            try {
                Object result = handlerMethod.invoke(exchange);
                if (result instanceof String) {
                    sendResponse(exchange, 200, (String) result);
                }
            } catch (Exception e) {
                log.error("Error handling request: {} {}", method, path, e);
                sendResponse(exchange, 500, "Internal Server Error");
            }
        } else {
            log.warn("No handler found for: {} {}", method, path);
            sendResponse(exchange, 404, "Not Found");
        }
    }

    /**
     * 查找匹配的处理器方法
     * @param httpMethod HTTP方法
     * @param path 路径
     * @return 处理器方法
     */
    private HandlerMethod findHandlerMethod(String httpMethod, String path) {
        // 精确匹配
        String key = httpMethod + ":" + path;
        if (handlerMethods.containsKey(key)) {
            return handlerMethods.get(key);
        }

        // 模式匹配
        for (Map.Entry<String, HandlerMethod> entry : handlerMethods.entrySet()) {
            String patternKey = entry.getKey();
            if (patternKey.startsWith(httpMethod + ":")) {
                String patternPath = patternKey.substring(httpMethod.length() + 1);
                PathPattern pathPattern = new PathPattern(patternPath);
                if (pathPattern.matches(path)) {
                    // 将路径变量信息存储在exchange属性中，供控制器使用
                    // Map<String, String> pathVariables = pathPattern.extractPathVariables(path);
                    return entry.getValue();
                }
            }
        }

        return null;
    }

    /**
     * 标准化路径
     * @param path 路径
     * @return 标准化后的路径
     */
    private String normalizePath(String path) {
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        return path.replaceAll("/+", "/");
    }

    /**
     * 发送 HTTP 响应
     * @param exchange HttpExchange 对象
     * @param statusCode 状态码
     * @param response 响应内容
     * @throws IOException IO异常
     */
    private void sendResponse(HttpExchange exchange, int statusCode, String response) throws IOException {
        byte[] responseBytes = response.getBytes();
        exchange.sendResponseHeaders(statusCode, responseBytes.length);
        try (var os = exchange.getResponseBody()) {
            os.write(responseBytes);
        }
    }

    /**
     * 路径模式匹配类
     */
    private static class PathPattern {
        private final Pattern regexPattern;
        private final List<String> variableNames;

        public PathPattern(String pattern) {
            this.variableNames = new ArrayList<>();

            // 将路径模式转换为正则表达式
            String regex = pattern;
            // 查找所有路径变量名
            Matcher variableMatcher = Pattern.compile("\\{([^/}]+)}").matcher(pattern);
            while (variableMatcher.find()) {
                variableNames.add(variableMatcher.group(1));
            }

            // 将 {variable} 替换为捕获组
            regex = regex.replaceAll("\\{[^/}]+}", "([^/]+)");
            this.regexPattern = Pattern.compile("^" + regex + "$");
        }

        public boolean matches(String path) {
            return regexPattern.matcher(path).matches();
        }

        public Map<String, String> extractPathVariables(String path) {
            Map<String, String> variables = new HashMap<>();
            Matcher matcher = regexPattern.matcher(path);

            if (matcher.matches()) {
                // 提取路径变量
                for (int i = 0; i < variableNames.size() && i < matcher.groupCount(); i++) {
                    variables.put(variableNames.get(i), matcher.group(i + 1));
                }
            }

            return variables;
        }
    }

    /**
     * 处理器方法内部类
     */
    private static class HandlerMethod {
        private final Object instance;
        private final Method method;

        public HandlerMethod(Object instance, Method method) {
            this.instance = instance;
            this.method = method;
        }

        public Object invoke(HttpExchange exchange) throws Exception {
            return method.invoke(instance, exchange);
        }
    }
}
